//
// Created by 吴喆 on 2020/3/14.
//
#import "DemoPlayerStateMachine.h"

DemoPlayerStateMachine *DemoPlayerStateMachine::machine = nullptr;

DemoPlayerStateMachine::DemoPlayerStateMachine() {
    currentState = new BirthState();
}

/*NOLINT*/

PlayableState *RunState::handleInput(Playable &playable, KeyEvent *event) {

    if (event->key == GLFW_KEY_RIGHT || event->key == GLFW_KEY_LEFT) {
        if (event->released) {
            return new StandState();
        }
    }
    if (event->key == GLFW_KEY_SPACE) {
        if ((Input::getInstance()->keyMap[GLFW_KEY_DOWN] && Input::getInstance()->keyMap[GLFW_KEY_DOWN]->held) && !playable.floor->isBottom) {
            playable.body.instance->GetFixtureList()->SetSensor(true);
            return new FallState();
        }
        if (event->down) {
            return new JumpState();
        }
    }
    return nullptr;
}

PlayableState *RunState::update(Playable &playable) {
    PlayableState::update(playable);
    if (playable.isAtk) {
        playable.currentAnimation = animationMap[1];
    } else {
        playable.currentAnimation = animationMap[0];
    }
    b2Vec2 desiredVel = b2Vec2(-playable.speed, playable.body.instance->GetLinearVelocity().y);// the vector speed you set
    if (playable.direction == DIRECTION::LEFT) {
        desiredVel = b2Vec2(playable.speed, playable.body.instance->GetLinearVelocity().y);// the vector speed you set
    }
    if (playable.body.currentPos.y < playable.body.lastPos.y) {
        return new FallState();
    }

    playable.body.instance->SetLinearVelocity(desiredVel);
    return nullptr;

}

void RunState::initAnimation() {
    auto animation = new Animation(100);
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Run_0.png"));
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Run_1.png"));
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Run_2.png"));
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Run_3.png"));
    animationMap.insert(std::make_pair(0, animation));
    auto animation1 = new Animation(100);
    animation1->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Run Atk_0.png"));
    animation1->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Run Atk_1.png"));
    animation1->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Run Atk_2.png"));
    animation1->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Run Atk_3.png"));
    animationMap.insert(std::make_pair(1, animation1));
}

void RunState::enter(Playable &playable) {
    PlayableState::enter(playable);
    if (playable.isAtk && animationMap.size() > 1) {
        playable.currentAnimation = animationMap[1];
    } else {
        playable.currentAnimation = animationMap[0];
    }
}


PlayableState *BirthState::handleInput(Playable &playable, KeyEvent *event) {
    return nullptr;
}

PlayableState *BirthState::update(Playable &playable) {
    PlayableState::update(playable);
    if (playable.currentAnimation->isOver) {
        return new StandState();
    }
    return nullptr;

}

void BirthState::initAnimation() {
    auto animation = new Animation(200, false);
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Spawn_0.png"));
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Spawn_1.png"));
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Spawn_2.png"));
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Spawn_3.png"));
    animationMap.insert(std::make_pair(0, animation));
}

//------------------------ stand
PlayableState *StandState::handleInput(Playable &playable, KeyEvent *event) {
    if (event->key == GLFW_KEY_RIGHT || event->key == GLFW_KEY_LEFT) {
        if (event->down || event->held) {
            return new RunState();
        }
    }
    if (event->key == GLFW_KEY_SPACE) {
        if (event->held) {
            if ((Input::getInstance()->keyMap[GLFW_KEY_DOWN] && Input::getInstance()->keyMap[GLFW_KEY_DOWN]->held)) {
                if (!playable.floor->isBottom) {
                playable.body.instance->GetFixtureList()->SetSensor(true);
                return new FallState();
                }
                return nullptr;
            }
            return new JumpState();
        }
    }

    return nullptr;
}

PlayableState *StandState::update(Playable &playable) {
    PlayableState::update(playable);
    if (playable.isAtk) {
        playable.currentAnimation = animationMap[1];
    } else {
        playable.currentAnimation = animationMap[0];
    }
    // 一个bug？按了空格别的键的held状态就不能唤醒了
    if ((Input::getInstance()->keyMap[GLFW_KEY_RIGHT] && Input::getInstance()->keyMap[GLFW_KEY_RIGHT]->held) ||
        (Input::getInstance()->keyMap[GLFW_KEY_LEFT] && Input::getInstance()->keyMap[GLFW_KEY_LEFT]->held)) {
        return new RunState();
    }
    if (playable.body.currentPos.y < playable.body.lastPos.y) {
        return new FallState();
    }
    return nullptr;
}


void StandState::initAnimation() {
    auto animation = new Animation(200, true);
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Stand_0.png"));
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Stand_1.png"));
    animationMap.insert(std::make_pair(0, animation));
    auto animation1 = new Animation(200, true);
    animation1->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Stand Atk_0.png"));
    animation1->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Stand Atk_1.png"));
    animationMap.insert(std::make_pair(1, animation1));
}

void StandState::enter(Playable &playable) {
    PlayableState::enter(playable);
    if (playable.isAtk && animationMap.size() > 1) {
        playable.currentAnimation = animationMap[1];
    } else {
        playable.currentAnimation = animationMap[0];
    }
}

PlayableState *JumpState::handleInput(Playable &playable, KeyEvent *event) {
    return nullptr;
}

PlayableState *JumpState::update(Playable &playable) {
    PlayableState::update(playable);
    if (playable.isAtk) {
        playable.currentAnimation = animationMap[1];
    } else {
        playable.currentAnimation = animationMap[0];
    }
    if (playable.body.currentPos.y <= playable.body.lastPos.y) {
        return new FallState();
    }
    return nullptr;
}

void JumpState::initAnimation() {
    auto animation = new Animation(50, false);
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Jump_0.png"));
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Jump_1.png"));
    animationMap.insert(std::make_pair(0, animation));
    auto animation1 = new Animation(50, false);
    animation1->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Jump Atk_0.png"));
    animation1->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Jump Atk_1.png"));
    animationMap.insert(std::make_pair(1, animation1));
}

void JumpState::enter(Playable &playable) {
    PlayableState::enter(playable);
    if (playable.isAtk && animationMap.size() > 1) {
        playable.currentAnimation = animationMap[1];
    } else {
        playable.currentAnimation = animationMap[0];
    }
    float m = playable.body.instance->GetMass();// the mass of the body
    b2Vec2 desiredVel = b2Vec2(0, 12);// the vector speed you set
    b2Vec2 impulse = m * desiredVel; //impulse = mv
//    playable.body.instance->GetFixtureList()->SetSensor(true);
    playable.body.instance->ApplyLinearImpulse(impulse, playable.body.instance->GetWorldCenter(), true);
}


PlayableState *FallState::handleInput(Playable &playable, KeyEvent *event) {
    return nullptr;
}

PlayableState *FallState::update(Playable &playable) {
    playable.body.instance->GetFixtureList()->SetSensor(false);
    PlayableState::update(playable);
    if (playable.isAtk) {
        playable.currentAnimation = animationMap[1];
    } else {
        playable.currentAnimation = animationMap[0];
    }
    // 掉到物体上
    if (playable.body.currentPos.y >= playable.body.lastPos.y) {
        return new StandState();
    }
    return nullptr;
}

void FallState::initAnimation() {
    auto animation = new Animation(50, false);
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Fall_0.png"));
    animation->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Fall_1.png"));
    animationMap.insert(std::make_pair(0, animation));
    auto animation1 = new Animation(50, false);
    animation1->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Fall Atk_0.png"));
    animation1->addFrame(ResourceManager::getTexture("player.Hero - 8x_Hero - Fall Atk_1.png"));
    animationMap.insert(std::make_pair(1, animation1));
}

void FallState::enter(Playable &playable) {

    PlayableState::enter(playable);
    if (playable.isAtk && animationMap.size() > 1) {
        playable.currentAnimation = animationMap[1];
    } else {
        playable.currentAnimation = animationMap[0];
    }
}
